<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
  <script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
  <script src="../js/babel.js"></script>
</head>

<body>
  <div id="root"></div>
</body>

</html>

<script type="text/babel">
  // Ref
  function RefChildCpn(props) {
    return (
      <div>
        <input type="text" ref={props.inputRef} />
      </div>
    )
  }

  // 子组件上设置一个ref 将这个DOM ref 暴露给父组件(props) 从而让父组件将ref传向子节点的DOM

  class RefParentCpn extends React.Component {
    constructor(props) {
      super(props)
      this.inputElement = React.createRef()  // 通过React.createRef() 函数创建ref

      this.handleClick = this.handleClick.bind(this)
    }

    handleClick() {
      this.inputElement.current.focus()
    }

    render() {
      return (
        <div>
          <p>测试ref聚焦</p>
          <button onClick={this.handleClick}>点击聚焦到输入框</button>
          <RefChildCpn inputRef={this.inputElement} />
        </div>
      )  // 将创建的ref 回调函数传入子组件中 这样就实现了DOM ref 的设定
    }
  }

  /**
   * 当使用HOC 来扩展组件时 我们建议用React 的forwardRef 函数来向被包裹的组件转发ref 
   * 如果第三方的HOC 不支持转发ref 上面的方法任可以作为一种备选方案
   */

  // 利用事件监听实现的
  class OuterClickExample extends React.Component {
    constructor(props) {
      super(props)
      this.state = { isShow: false }
      this.selectArea = React.createRef()

      this.handleClickBtn = this.handleClickBtn.bind(this)
      this.handleOuterClick = this.handleOuterClick.bind(this)
    }

    componentDidMount() {
      window.addEventListener('click', this.handleOuterClick)
    }

    componentWillUnmount() {
      window.removeEventListener('click', this.handleOuterClick)
    }

    handleClickBtn() {
      this.setState(currentState => ({
        isShow: !currentState.isShow
      }), () => {
        console.log('实时', this.state.isShow);
        // 这里能够拿到实时的state里面的数据
      })

      console.log('还未修改的数据', this.state.isShow);
    }

    handleOuterClick(event) {
      if (this.state.isShow && !this.selectArea.current.contains(event.target)) {
        this.setState({
          isShow: false
        })
      }
    }

    render() {
      return (
        <div ref={this.selectArea}>
          <button onClick={this.handleClickBtn}>visible option at click me </button>
          {this.state.isShow &&
            (<ul>
              <li>options1</li>
              <li>options2</li>
              <li>options3</li>
            </ul>)
          }
        </div>
      )
    }
  }

  // 利用事件触发器实现控制
  class OuterClickExample2 extends React.Component {
    constructor(props) {
      super(props);

      this.state = { isOpen: false };
      this.timeOutId = null;

      this.onClickHandler = this.onClickHandler.bind(this);
      this.onBlurHandler = this.onBlurHandler.bind(this);
      this.onFocusHandler = this.onFocusHandler.bind(this);
    }

    onClickHandler() {
      this.setState(currentState => ({
        isOpen: !currentState.isOpen
      }));
    }

    // 我们在下一个时间点使用 setTimeout 关闭弹窗。
    // 这是必要的，因为失去焦点事件会在新的焦点事件前被触发，
    // 我们需要通过这个步骤确认这个元素的一个子节点
    // 是否得到了焦点。
    onBlurHandler() {
      this.timeOutId = setTimeout(() => {
        this.setState({
          isOpen: false
        });
      });
    }

    // 如果一个子节点获得了焦点，不要关闭弹窗。
    onFocusHandler() {
      clearTimeout(this.timeOutId);
    }

    render() {
      // React 通过把失去焦点和获得焦点事件传输给父节点
      // 来帮助我们。
      return (
        <div onBlur={this.onBlurHandler}
          onFocus={this.onFocusHandler}>
          <button onClick={this.onClickHandler}
            aria-haspopup="true"
            aria-expanded={this.state.isOpen}>
            Select an option
        </button>
          {this.state.isOpen && (
            <ul>
              <li>Option 1</li>
              <li>Option 2</li>
              <li>Option 3</li>
            </ul>
          )}
        </div>
      );
    }
  }

  ReactDOM.render(<OuterClickExample2 />, document.getElementById('root'))


</script>